/**
 * 
 */
package pruebas.tiendaOl.dominio.entidades;

import iades.fabricaciones.Entidad;
import iades.fabricaciones.UnidadTrabajo;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.enterprise.context.Dependent;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.persistence.Transient;

import pruebas.tiendaOl.dominio.calificadores.CalEvento.Agregado;
import pruebas.tiendaOl.dominio.calificadores.CalEvento.Modificado;
import pruebas.tiendaOl.dominio.calificadores.CalEvento.Quitado;
import pruebas.tiendaOl.dominio.repositorios.RepoGondola;

/** @author Gustavo */
@Dependent
public class Gondola implements Serializable, Entidad<Gondola> {
	@Inject
	private transient RepoGondola repoGondola;
	@Inject
	private UnidadTrabajo ut;

	private Map<TipoArticulo, ItemGondola> items = null;
	private Map<TipoArticulo, ItemGondola> getItems() {
		if (this.items == null) {
			items = new HashMap<TipoArticulo, ItemGondola>();
			for (ItemGondola item : repoGondola.conseguirTodos()) {
				assert ut.contiene(item);
				this.items.put(item.getTipoArticulo(), item);
			}
		}
		return this.items;
	}

	@Transient
	public Map<TipoArticulo, ItemGondola> getItems_const() {
		return Collections.unmodifiableMap(this.getItems());
	}

	public int ponerArticulos(TipoArticulo tipoArticulo, int cantidadSePretendeAgregar) {
		assert cantidadSePretendeAgregar >= 0;
		assert ut.contiene(tipoArticulo);
		ItemGondola itemGondola = this.getItems().get(tipoArticulo);
		if (itemGondola == null) {
			this.getItems().put(tipoArticulo, repoGondola.crearNuevoItem(tipoArticulo, cantidadSePretendeAgregar));
			this.lanzadorEventosItemAgregado.fire(new EventoGondola(tipoArticulo, cantidadSePretendeAgregar));
			return cantidadSePretendeAgregar;
		} else {
			assert ut.contiene(itemGondola);
			int cantidadFinal = cantidadSePretendeAgregar + itemGondola.getCantidad();
			itemGondola.setCantidad(cantidadFinal);
			this.lanzadorEventosItemModificado.fire(new EventoGondola(tipoArticulo, cantidadSePretendeAgregar));
			return cantidadFinal;
		}
	}

	public int sacarArticulos(TipoArticulo tipoArticulo, int cantidadSePretendeSacar) {
		assert cantidadSePretendeSacar >= 0;
		assert ut.contiene(tipoArticulo);
		ItemGondola itemGondola = this.getItems().get(tipoArticulo);
		if (itemGondola == null)
			return 0;
		else {
			assert ut.contiene(itemGondola);
			Integer cantidadExistente = itemGondola.getCantidad();
			int cantidadSacada = Math.min(cantidadSePretendeSacar, cantidadExistente);
			itemGondola.setCantidad(cantidadExistente - cantidadSacada);
			if (itemGondola.getCantidad() == 0) {
				this.ut.quitar(this.items.remove(tipoArticulo));
				this.lanzadorEventosItemQuitado.fire(new EventoGondola(tipoArticulo, -cantidadSacada));
			} else
				this.lanzadorEventosItemModificado.fire(new EventoGondola(tipoArticulo, -cantidadSacada));
			return cantidadSacada;
		}
	}


	@Inject
	@Agregado
	private Event<EventoGondola> lanzadorEventosItemAgregado;
	@Inject
	@Quitado
	private Event<EventoGondola> lanzadorEventosItemQuitado;
	@Inject
	@Modificado
	private Event<EventoGondola> lanzadorEventosItemModificado;

	public static class EventoGondola {
		/**Tipo de articulo cuya cantidad de unidades existentes en la góndola ha cambiado. */
		public final TipoArticulo tipoArticulo;
		/**Es positivo si se han agregado articulos a la gondola, y negativo si se han quitado. */
		public final int cantidadAgregada;
		/**@param tipoArticulo tipo de articulo cuya cantidad de unidades existentes en la góndola ha cambiado
		 * @param cantidadAgregada debe ser positivo si se han agregado articulos a la gondola, y negativo si se han quitado */
		EventoGondola(TipoArticulo tipoArticulo, int cantidadAgregada) {
			this.tipoArticulo = tipoArticulo;
			this.cantidadAgregada = cantidadAgregada;
		}
	}


	//////////////// Debug /////////////
	@Inject
	private Logger logger;

	@PostConstruct
	void postConstruct() {
		logger.info("postConstruct Gondola#" + System.identityHashCode(this));
	}
}
